namespace lty
{
    template <class T>
    class SmartPtr
    {
    public:
        SmartPtr(T* ptr= nullptr)
        :_ptr(ptr){};
        ~SmartPtr()
        {
            if(_ptr)
                cout<< "delete:"<< _ptr << endl;
                delete _ptr;
        }
        T& operator*()
        {
            return *_ptr;
        }
        T* operator->()
        {
            return _ptr;
        }
    private:
        T* _ptr;
    };

    template <class T>
    class unique_ptr
    {
    public:
        unique_ptr(T* ptr= nullptr)
                :_ptr(ptr){};
        unique_ptr(const unique_ptr<T>& up)=delete;
        ~unique_ptr()
        {
            if(_ptr)
                cout<< "delete:"<< _ptr << endl;
            delete _ptr;
        }
        T& operator*()
        {
            return *_ptr;
        }
        T* operator->()
        {
            return _ptr;
        }
    private:
        T* _ptr;
    };

    template<class T>
    class shared_ptr
    {
    public:
        shared_ptr(T* ptr = nullptr)
                :_ptr(ptr)
                , _pcount(new int(1))
                , _pmtx(new mutex)
        {}

        template<class D>
        shared_ptr(T* ptr, D del)
                :_ptr(ptr)
                , _pcount(new int(1))
                , _pmtx(new mutex)
                , _del(del)
        {}

        ~shared_ptr()
        {
            Release();
        }

        void Release()
        {
            _pmtx->lock();

            bool deleteFlag = false;

            if (--(*_pcount) == 0)//如果左值是最后一个指向该空间的值，那么被重新赋值后此空间就无法找到，必须释放
            {
                if (_ptr)
                {
                    //cout << "delete:" << _ptr << endl;
                    //delete _ptr;

                    // 删除器进行删除
                    _del(_ptr);
                }

                delete _pcount;
                deleteFlag = true;
            }

            _pmtx->unlock();

            if (deleteFlag)
            {
                delete _pmtx;
            }
        }

        void AddCount()
        {
            _pmtx->lock();

            ++(*_pcount);

            _pmtx->unlock();
        }

        shared_ptr(const shared_ptr<T>& sp)
                :_ptr(sp._ptr)
                , _pcount(sp._pcount)
                , _pmtx(sp._pmtx)
        {
            AddCount();
        }

        shared_ptr<T>& operator=(const shared_ptr<T>& sp)
        {
            if (_ptr != sp._ptr)
            {
                Release();

                _ptr = sp._ptr;
                _pcount = sp._pcount;
                _pmtx = sp._pmtx;

                AddCount();
            }

            return *this;
        }

        T& operator*()
        {
            return *_ptr;
        }

        T* operator->()
        {
            return _ptr;
        }

        T* get() const
        {
            return _ptr;
        }

        int use_count()
        {
            return *_pcount;
        }

    private:
        T* _ptr;
        int* _pcount;
        mutex* _pmtx;

        // 包装器
        function<void(T*)> _del = [](T* ptr){delete ptr;};
    };

    void test_ptr()
    {
        SmartPtr<int> sp1(new int);
    }

}
